/***********************************************
*	名称:排序-任意类型
*	说明:可以排序任意类型的切片
*	作者:钱纯净
************************************************/

package sort

import (
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/injoyai/goutil/conv"
	"sort"
)

type SortAnyModel struct {
	list []interface{}                       //列表
	fn   func(interface{}, interface{}) bool //排序条件
	err  error                               //错误信息
}

func New(fn func(a, b interface{}) bool) *SortAnyModel {
	return &SortAnyModel{fn: fn}
}

// NewVar 排序,conv.Var 版本
func NewVar(fn func(a, b *conv.Var) bool) *SortAnyModel {
	return &SortAnyModel{fn: func(c, d interface{}) bool {
		return fn(conv.New(c), conv.New(d))
	}}
}

// SortAny 任意类型排序,需要指针类型(测试)
func SortAny(i interface{}, key string, desc ...bool) error {
	if !conv.IsArray(i) {
		return errors.New("类型错误不能排序:" + conv.String(i))
	}
	if !conv.IsPointer(i) {
		return errors.New("需要指针类型")
	}
	list := conv.Interfaces(i)
	if len(list) > 0 {
		if len(key) > 0 {
			return SortMap(key, desc...).Bind(i)
		} else if conv.IsNumber(list[0]) {
			return SortNumber(desc...).Bind(i)
		} else if conv.IsString(list[0]) {
			return New(func(a, b interface{}) bool {
				x := conv.New(a).String() > conv.New(b).String()
				if !(len(desc) > 0 && desc[0]) {
					x = !x
				}
				return x
			}).Bind(i)
		}
	}
	return nil
}

// SortNumber 排序数字类型
func SortNumber(desc ...bool) *SortAnyModel {
	return New(func(a, b interface{}) bool {
		x := conv.New(a).Float64() > conv.New(b).Float64()
		if !(len(desc) > 0 && desc[0]) {
			x = !x
		}
		return x
	})
}

// SortStruct 排序结构体
func SortStruct(key string, desc ...bool) *SortAnyModel {
	return SortMap(key, desc...)
}

// SortMap 排序字典,同结构体
func SortMap(key string, desc ...bool) *SortAnyModel {
	return New(func(a, b interface{}) bool {
		x := false
		ax := conv.NewMap(a).Get(key)
		bx := conv.NewMap(b).Get(key)
		if ax.Var.IsNumber() {
			x = ax.Float64() > bx.Float64()
		} else {
			x = ax.String() > bx.String()
		}
		if !(len(desc) > 0 && desc[0]) {
			x = !x
		}
		return x
	})
}

// Add 需要[]interface类型,或者任意类型的子元素
func (this *SortAnyModel) Add(list ...interface{}) *SortAnyModel {
	for _, v := range list {
		this.list = append(this.list, conv.Interfaces(v)...)
	}
	return this
}

func (this *SortAnyModel) Set(list []interface{}) *SortAnyModel {
	this.list = list
	return this
}

func (this *SortAnyModel) Sort() ([]interface{}, error) {
	sort.Sort(this)
	return this.list, this.err
}

func (this *SortAnyModel) Bind(pointer interface{}) error {
	this.Add(pointer)
	data, err := this.Sort()
	if err != nil {
		return err
	}
	bs, err := json.Marshal(data)
	if err != nil {
		return err
	}
	return json.Unmarshal(bs, pointer)
}

//------------------------

// Len 实现自带排序接口
func (this *SortAnyModel) Len() int {
	return len(this.list)
}

// Less 实现自带排序接口
func (this *SortAnyModel) Less(i, j int) bool {
	defer this.recover()
	return this.fn(this.list[i], this.list[j])
}

// Swap 实现自带排序接口
func (this *SortAnyModel) Swap(i, j int) {
	this.list[i], this.list[j] = this.list[j], this.list[i]
}

// recover 捕捉错误(主要类型强转错误)
func (this *SortAnyModel) recover() {
	if err := recover(); err != nil {
		this.err = errors.New(fmt.Sprintln(err))
	}
}
